﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NTerm
{
    /// <summary>
    /// Defines a data structure representing a Rectangle shape
    /// </summary>
    public struct Rectangle
    {
        /// <summary>
        /// X position
        /// </summary>
        public int x;

        /// <summary>
        /// The Y position
        /// </summary>
        public int y;

        /// <summary>
        /// The width of the recangle
        /// </summary>
        public int w;

        /// <summary>
        /// The height of the rectangle
        /// </summary>
        public int h;

        /// <summary>
        /// Creates an instance of a Rectangle
        /// </summary>
        /// <param name="x">The X offset</param>
        /// <param name="y">The Y offset</param>
        /// <param name="width">The width of the rectangle</param>
        /// <param name="height">The height of the rectangle</param>
        public Rectangle(int x, int y, int width, int height)
        {
            this.x = x;
            this.y = y;
            this.w = width;
            this.h = height;
        }

        /// <summary>
        /// Gets whether the rectangle is null (-1, -1, -1, -1)
        /// </summary>
        /// <returns>Returns true if the rectangle is null</returns>
        public bool IsNull()
        {
            return (x == -1 && y == -1 && w == -1 && h == -1);
        }

        /// <summary>
        /// Creates an instance of a null rectangle
        /// </summary>
        /// <returns>A reference of the created null rectangel instance</returns>
        public static Rectangle GetNullValue()
        {
            return new Rectangle(-1, -1, -1, -1);
        }

        /// <summary>
        /// Gets the rectangle of the intersection between 2 rectangles
        /// </summary>
        /// <param name="rectA">First rectangle</param>
        /// <param name="rectB">Second rectangle</param>
        /// <returns>A new rectangle that represents the intersection of rectA and rectB</returns>
        public static Rectangle operator &(Rectangle rectA, Rectangle rectB)
        {
            Rectangle result = Rectangle.GetNullValue();

            // Check if the 2 rectangles are overlapping, else return a null triangle

            // Rectangle A does not overlap Rectangle B
            if (rectA.x > (rectB.x + rectB.w) && rectA.y > (rectB.y + rectB.h))
                return result;

            // Rectangle B does not overlap Rectangle A
            if (rectB.x > (rectA.x + rectA.w) && rectB.y > (rectA.y + rectA.h))
                return result;

            // First determine what our intersecting X,Y
            // We will always get the X,Y postion of the furthest rectangle

            result.x = Math.Max(rectA.x, rectB.x);
            result.y = Math.Max(rectA.y, rectB.y);
            
            // Now determine the width and height of the intersection rectangle
            // The size by will alwasy be the smallest area between the result X,Y coord and one of the rectangle's bottom-right X,Y coord.  
            // Otherwise the rectangles have the same position and size

            result.w = Math.Min((rectA.x + rectA.w) - result.x, (rectB.x + rectB.w) - result.x);
            result.h = Math.Min((rectA.y + rectA.h) - result.y, (rectB.y + rectB.h) - result.y);

            return result;
        }

        /// <summary>
        /// Gets the rectangle of the intersection between 2 rectangles
        /// </summary>
        /// <param name="rectA">First rectangle</param>
        /// <param name="rectB">Second rectangle</param>
        /// <returns>A new rectangle that represents the intersection of rectA and rectB</returns>
        public static Rectangle BitwiseAnd(Rectangle rectA, Rectangle rectB)
        {
            return rectA & rectB;
        }

        /// <summary>
        /// Determines whether this instance and another specified object, which has to be a type of Rectangle, are the same value
        /// </summary>
        /// <param name="obj">The Rectangle to compare this instance</param>
        /// <returns>true if obj is a Rectangle and its value is the same as this instance; otherwise, false</returns>
        public override bool Equals(object obj)
        {
            Rectangle rect = (Rectangle)obj;
            return x.Equals(rect.x) && y.Equals(rect.y) && w.Equals(rect.w) && h.Equals(rect.h);
        }

        /// <summary>
        /// Returns a hash code for this Rectangle
        /// </summary>
        /// <returns>A 32-bit signed integer hash code</returns>
        public override int GetHashCode()
        {
            return (x ^ y) ^ (w ^ h);
        }

        /// <summary>
        /// Converts the Rectangle value of this instance to its equivalent string representation.
        /// </summary>
        /// <returns>Returns the string representation of the the value of this instance</returns>
        public override string ToString()
        {
            return String.Format("{{0}, {1}, {2}, {3}}", new object[] { x, y, w, h });
        }
        
        /// <summary>
        /// overriden
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator ==(Rectangle a, Rectangle b)
        {
            return a.Equals(b);
        }

        /// <summary>
        /// overriden
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool operator !=(Rectangle a, Rectangle b)
        {
            return !(a == b);
        }
    }
}
